# coding: utf-8

import time, sys, os

sys.path.append(os.getcwd())
sys.path.append(os.getcwd() + '/../')

from HPSocket import TcpPull
from HPSocket import helper
import HPSocket.pyhpsocket as HPSocket
import random
import json

class Pack:
    PROTOCOL_OFFSET_ADDRESS_LEN = 0  # 长度地址偏移
    PROTOCOL_OFFSET_ADDRESS_API = 4  # API地址偏移
    PROTOCOL_OFFSET_ADDRESS_SEND_TYPE = 6  # API地址偏移
    PROTOCOL_OFFSET_ADDRESS_FLAG = 8  # 标识地址偏移
    PROTOCOL_OFFSET_ADDRESS_DATA = 16  # 数据地址偏移
    PROTOCOL_HEADER_SIZE = 16

    PACK_FLAG_TYPE_ASYN = 10  # 异步类型
    PACK_FLAG_TYPE_SYNC = 11  # 同步类型
    PACK_FLAG_TYPE_RESPONSE = 12  # 响应类型

    def __init__(self):
        pass

    def Api_GetTotal_Size(self, pDate: bytes, off=0):
        total = pDate[off + self.PROTOCOL_OFFSET_ADDRESS_LEN:off + self.PROTOCOL_OFFSET_ADDRESS_LEN + 4]
        total = int.from_bytes(total, byteorder='little')
        return total

    def Api_GetApiCode(self, pDate: bytes, off=0):
        api_code = pDate[off + self.PROTOCOL_OFFSET_ADDRESS_API:off + self.PROTOCOL_OFFSET_ADDRESS_API + 2]
        api_code = int.from_bytes(api_code, byteorder='little')
        return api_code

    def Api_GetSendType(self, pDate: bytes, off=0):
        send_type = pDate[off + self.PROTOCOL_OFFSET_ADDRESS_SEND_TYPE:off + self.PROTOCOL_OFFSET_ADDRESS_SEND_TYPE + 2]
        send_type = int.from_bytes(send_type, byteorder='little')
        return send_type

    def Api_GetPackFlag(self, pDate: bytes, off=0):
        flag = pDate[off + self.PROTOCOL_OFFSET_ADDRESS_FLAG:off + self.PROTOCOL_OFFSET_ADDRESS_FLAG + 8]
        flag = int.from_bytes(flag, byteorder='little')
        return flag

    def Api_GetPackData(self, pDate: bytes, off=0):
        data = pDate[off + self.PROTOCOL_OFFSET_ADDRESS_DATA:]
        return data

    def Api_CreatePackFlag(self):
        s = ''
        for i in range(16):
            if i == 0:
                s = str(random.randint(1, 9))
            else:
                s = s + str(random.randint(0, 9))
        resdata = int(s)
        return resdata

    def Api_CreatePack(self, apiCode: int,sendType, packFlag: int, data: bytes):
        length = len(data) + 4
        d = length.to_bytes(4, byteorder="little")
        d = d + apiCode.to_bytes(2, byteorder="little")
        d = d + sendType.to_bytes(2, byteorder="little")
        d = d + packFlag.to_bytes(8, byteorder="little")
        return d + data

    def Api_DataUnPack(self, pData: bytes):
        pCurrent = 0
        Resdata = bytes()
        ApiCode = 0
        flag = 0
        send_type = 0
        received_size = len(pData)
        while True:
            if (received_size - pCurrent < self.PROTOCOL_HEADER_SIZE):
                break
            Total_Size = self.Api_GetTotal_Size(pDate=pData, off=pCurrent)
            if Total_Size + self.PROTOCOL_HEADER_SIZE - 4 > received_size - pCurrent:
                break
            ApiCode = self.Api_GetApiCode(pDate=pData, off=pCurrent)
            send_type=self.Api_GetSendType(pDate=pData, off=pCurrent)
            flag = self.Api_GetPackFlag(pDate=pData, off=pCurrent)
            ResData_Length = Total_Size - 4
            if ResData_Length > 0:
                Resdata = self.Api_GetPackData(pDate=pData, off=pCurrent)
            pCurrent = pCurrent + Total_Size + self.PROTOCOL_HEADER_SIZE - 4
        return (received_size - pCurrent, ApiCode, send_type, flag, Resdata)

class Receive:
    def __init__(self):
        self.Pack = Pack()
        self.data = bytes()
        self.Response = []

    def GetResponse(self, flag:int, outTime=5):
        t = time.time()
        rData = None
        while True:
            for i in range(len(self.Response)):
                if self.Response[i]["flag"] == flag:
                    data = self.Response.pop(i)
                    rData = data["data"]
                    break
            if rData:
                break
            if time.time() - t > outTime:
                break
        return rData

    def _Recevie(self, pData: bytes):
        self.data = self.data + pData
        if len(self.data) < self.Pack.PROTOCOL_HEADER_SIZE:
            return 0
        (length, ApiCode, send_type, flag, resdata) = self.Pack.Api_DataUnPack(pData=self.data)
        print()
        if length == 0:
            if not flag == 0:
                if send_type == self.Pack.PACK_FLAG_TYPE_RESPONSE:
                    print("收到响应包",flag)
                    self.Response.append({
                        "flag": flag,
                        "data": resdata
                    })
                elif send_type == self.Pack.PACK_FLAG_TYPE_SYNC:
                    '''这里处理同步逻辑'''
                    msg={"code":200,"msg":"sucess"}
                    msg=json.dumps(msg)
                    cnt.Answer(flag=flag,data=msg.encode())
                    pass
                else:
                    pass
            print("收到数据", resdata.decode())
            self.data = bytes()
        else:
            self.data = self.data[len(self.data) - length:]
        return 0

class Client(TcpPull.HP_TcpPullClient):
    def __init__(self):
        super().__init__()
        self._Recevie = Receive()
        self.Pack = Pack()
        self.COLOSE = True

    @TcpPull.HP_TcpPullServer.EventDescription
    def Start(self, host, port):
        if super().Start(host, port):
            print('Start server success, listen on %s:%d' % (host, port))
        else:
            print('Start server fail.')

    @TcpPull.HP_TcpPullClient.EventDescription
    def OnClose(self, Sender, ConnID, Operation, ErrorCode):
        print('断开连接：%d' % ErrorCode)
        self.COLOSE = True
        return HPSocket.EnHandleResult.HR_OK

    @TcpPull.HP_TcpPullClient.EventDescription
    def OnConnect(self, Sender, ConnID):
        print('Connected.')
        self.COLOSE = False
        return HPSocket.EnHandleResult.HR_OK

    @TcpPull.HP_TcpPullClient.EventDescription
    def OnReceive(self, Sender, ConnID, Length):
        print("数据到达", Sender, ConnID, Length)
        result = HPSocket.HP_TcpPullClient_Fetch(Sender, Length)  # 这里获取 Body
        return self._Recevie._Recevie(result)

    def Sync_SendData(self, data:bytes):
        packFlag = self.Pack.Api_CreatePackFlag()
        pData = self.Pack.Api_CreatePack(apiCode=999,
                                         sendType=self.Pack.PACK_FLAG_TYPE_SYNC,
                                         packFlag=packFlag,
                                         data=data)
        self.Send(self.Client, pData)
        Response = self._Recevie.GetResponse(flag=packFlag, outTime=15)
        return Response

    def Answer(self,flag:int,data:bytes):
        pData = self.Pack.Api_CreatePack(apiCode=999,
                                         sendType=self.Pack.PACK_FLAG_TYPE_RESPONSE,
                                         packFlag=flag,
                                         data=data)
        return self.Send(self.Client, pData)

    def SendData(self, data:bytes):
        packFlag = self.Pack.Api_CreatePackFlag()
        pData = self.Pack.Api_CreatePack(apiCode=999,
                                         sendType=self.Pack.PACK_FLAG_TYPE_ASYN,
                                         packFlag=packFlag,
                                         data=data)
        return self.Send(self.Client, pData)

if __name__ == '__main__':
    cnt = Client()
    cnt.Start('127.0.0.1', 7889)
    msg = ''
    for i in range(1):
        msg = msg + "\n" + ""
    msg = msg.encode()
    i=0


    while cnt.COLOSE == False:
        # time.sleep(30)

        if(i%2==0):
            msg = "序号【%d】：我是客户端，请求数据！"%(i)
            msg = msg.encode()
            Response=cnt.Sync_SendData(msg)
        else:
            msg = "序号【%d】：我是客户端，测试数据！"%(i)
            msg = msg.encode()
            Response = cnt.SendData(msg)
        print("清求回复：",Response)
        i+=1
        time.sleep(15)
    print("运行完毕！")
